home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
019a
/
tde10src.zip
/
UTILS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
43KB
|
1,442 lines
/******************* start of original comments ********************/
/*
* Written by Douglas Thomson (1989/1990)
*
* This source code is released into the public domain.
*/
/*
* Name: dte - Doug's Text Editor program - miscellaneous utilities
* Purpose: This file contains miscellaneous functions that were required
* in more than one of the other files, or were thought to be
* likely to be used elsewhere in the future.
* File: utils.c
* Author: Douglas Thomson
* System: this file is intended to be system-independent
* Date: October 1, 1989
*/
/********************* end of original comments ********************/
/*
* The utility routines have been EXTENSIVELY rewritten. Update screens as
* needed. Most times, only one line has changed. Just show changed line
* in all windows if it is on screen.
*
* Support routines for text lines longer than screen width have been added.
* Currently support lines as long as 255 bytes. If longer lines are needed,
* the assembly routines need to be modified since they use bytes (a byte
* goes from 255 to 0, unsigned).
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
#include "tdestr.h"
#include "common.h"
#include "define.h"
#include "funcdef.h"
#include "tdefunc.h"
#ifdef __TURBOC__
#include <dir.h> /* for making temporary file names etc */
#endif
#if defined( __MSC__ )
#include <dos.h>
#include <io.h>
#endif
/*
* Name: myisalnum
* Purpose: To determine whether or not a character is part of a "word",
* which in languages like Pascal means a letter, digit or
* underscore.
* Date: October 1, 1989
* Passed: c: the character to be tested
* Returns: TRUE if c is an alphanumeric or '_' character, FALSE otherwise
*/
int myisalnum( c )
int c;
{
int rc;
rc = FALSE;
if (isalnum( c ) || (c == '_'))
rc = TRUE;
return( rc );
}
/*
* Name: check_virtual_col
* Purpose: make sure real column is displayed on screen
* Date: June 5, 1991
* Passed: window: current window
* rcol: real column of cursor
* ccol: current or logical column of cursor
*/
void check_virtual_col( window, rcol, ccol )
windows *window;
int rcol, ccol;
{
int bcol, ncols;
bcol = window->bcol;
ncols = g_display.ncols - 1;
/*
* is logical column past end of screen?
*/
if (ccol > ncols) {
ccol = ccol - bcol;
if (ccol > ncols) {
ccol = ncols;
bcol = rcol - ccol;
window->dirty = LOCAL;
}
/*
* is logical column behind start of screen?
*/
} else if (ccol < 0) {
if (bcol >= -ccol)
bcol += ccol;
ccol = 0;
window->dirty = LOCAL;
/*
* is current column < base column?
*/
} else if (rcol < bcol) {
ccol = rcol;
bcol = 0;
if (ccol > ncols) {
bcol = rcol - ncols;
ccol = rcol - bcol;
}
window->dirty = LOCAL;
}
/*
* current column + base column MUST equal real column
*/
if (ccol + bcol != rcol) {
if (bcol < 0)
bcol = rcol;
ccol = rcol - bcol;
if (ccol > ncols) {
bcol = rcol - ncols;
ccol = rcol - bcol;
}
window->dirty = LOCAL;
}
window->bcol = bcol;
window->ccol = ccol;
window->rcol = rcol;
}
/*
* Name: copy_line
* Purpose: To copy the cursor line, if necessary, into the current line
* buffer, so that changes can be made efficiently.
* Date: June 5, 1991
* Passed: text_line: line to be copied to line buffer
* line: line to display error message
* Notes: See un_copy_line, the reverse operation. Terminate text strings
* with CONTROL_Z. DO NOT use the C library string functions on
* text in g_status.line_buff.
*/
void copy_line( text_line, line )
text_ptr text_line;
int line;
{
text_ptr d, s; /* destination and source of copy */
int count; /* number of characters copied */
/*
* copy the cursor line to the line buffer
*/
d = g_status.line_buff;
s = cpf( text_line );
for (count=0; *s != CONTROL_Z; count++, s++) {
if (count >= g_display.line_length) {
*d++ = '\n';
error( WARNING, line, "line buffer overflow - line truncated!" );
break;
}
if (*s == '\n') {
*d++ = *s;
break;
}
/*
* d is incremented after *d = *s, fyi
*/
*d++ = *s;
}
*d = CONTROL_Z;
}
/*
* Name: un_copy_line
* Purpose: To copy the cursor line, if necessary, from the current line
* buffer, shifting the main text to make the right amount of
* room.
* Date: June 5, 1991
* Passed: test_line: pointer to location to copy line buffer
* prompt_line: line to display error message
* Notes: For various reasons, trailing spaces are NOT removed when
* returning the line buffer to the main text. Typically,
* padding is added at the end of a line by deliberately
* adding trailing spaces, and then uncopying the line.
* See copy_line, the reverse operation.
*/
void un_copy_line( text_line, prompt_line )
text_ptr text_line;
int prompt_line;
{
text_ptr source; /* source for block move and for copying buffer line */
text_ptr dest; /* destination for block move and copy */
long number; /* length of block move */
int space;
int len; /* length of current line buffer text */
int curs_len; /* length of cursor line */
/*
* work out the lengths of the old cursor line (including the \n if any)
* and the new current line buffer text.
*/
text_line = cpf( text_line );
curs_len = linelen( text_line );
if (text_line[curs_len] == '\n')
++curs_len;
len = find_CONTROL_Z( g_status.line_buff );
space = len - curs_len;
/*
* if the main text buffer has run out of space, then only part of the
* current line can be moved back into the main buffer. Warn the user
* that some of the current line has been lost
*/
if (ptoul( g_status.end_mem ) + (long)space >= ptoul( g_status.max_mem )) {
error( WARNING, prompt_line, "buffer full, part line truncated" );
len = curs_len + (int) (ptoul( g_status.max_mem ) -
ptoul( g_status.end_mem ));
}
/*
* move text to either make room for the extra characters in the new
* line, or else close up the gap.
*/
source = text_line + curs_len;
dest = addltop( (long)space, source );
number = ptoul( g_status.end_mem ) - ptoul( source );
hw_move( dest, source, number );
g_status.end_mem = addltop( (long)space, g_status.end_mem );
/*
* now copy the line buffer into the space just created
*/
source = g_status.line_buff;
dest = text_line;
for (; len > 0; len--)
*dest++ = *source++;
}
/*
* Name: load_file
* Purpose: To read in a given file to the end of the main text buffer.
* Date: June 5, 1991
* Passed: name: path name of file to be read
* Returns: OK if file read successfully
* ERROR if any problem (such as out of buffer space)
* Notes: If the file does not exist, the user is informed of an error,
* so check first if it is OK for the file to be new.
*/
int load_file( name )
char *name;
{
int line; /* line on screen to display prompt */
int rc;
rc = OK;
line = g_display.nlines;
/*
* make sure this gets set properly even if there is no file!
*/
g_status.temp_end = g_status.end_mem;
if (hw_load( name, g_status.end_mem, g_status.max_mem,
&g_status.temp_end, line ) == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: set_prompt
* Purpose: To display a prompt, highlighted, at the bottom of the screen.
* Date: October 1, 1989
* Passed: prompt: prompt to be displayed
* line: line on which to display prompt
*/
void set_prompt( prompt, line )
char *prompt;
int line;
{
/*
* work out where the answer should go
*/
g_status.prompt_col = strlen( prompt );
g_status.prompt_line = line;
/*
* output the prompt
*/
s_output( prompt, line, 0, g_display.message_color );
eol_clear( g_status.prompt_col, line, g_display.message_color );
/*
* ensure the cursor is in the right place
*/
xygoto( g_status.prompt_col, g_status.prompt_line );
}
/*
* Name: get_name
* Purpose: To prompt the user, and read the string the user enters in
* response.
* Date: October 1, 1989
* Passed: prompt: prompt to offer the user
* lines: no. of lines up from the bottom of the screen
* name: default answer
* color: color to display prompt
* Returns: name: user's answer
* OK if user entered something
* ERROR if user aborted the command
* Notes: Editing of the line is supported.
*/
int get_name( prompt, line, name, color )
char *prompt;
int line;
char *name;
int color;
{
int col; /* cursor column for answer */
int c; /* character user just typed */
char *cp; /* cursor position in answer */
char *answer; /* user's answer */
int first = TRUE; /* first character typed */
int len; /* length of answer */
int plen; /* length of prompt */
int func; /* function of key pressed */
char *p; /* for copying text in answer */
char buffer[MAX_COLS+2];/* line on which name is being entered */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
int normal;
/*
* set up prompt and default
*/
strcpy( buffer, prompt );
plen = strlen( prompt );
answer = buffer + plen;
strcpy( answer, name );
/*
* let user edit default into desired string
*/
len = strlen( answer );
col = strlen( buffer );
cp = answer + len;
c = 0;
normal = g_display.text_color;
save_screen_line( 0, line, line_buff );
s_output( buffer, line, 0, color );
eol_clear( col, line, normal );
while (key_func[c].func != AbortCommand && key_func[c].func != Rturn) {
xygoto( col, line );
c = (c=getch()) != 0 ? c : getch() | 0x100;
func = key_func[c].func;
switch (func) {
case ToggleSearchCase :
if (bm.search_case == IGNORE)
bm.search_case = MATCH;
else
bm.search_case = IGNORE;
show_search_case( );
break;
case Rturn :
answer[len] = '\0';
strcpy( name, answer );
/*
* finished
*/
break;
case BackSpace :
/*
* delete to left of cursor
*/
if (cp > answer) {
for (p=cp-1; p < answer+len; p++) {
*p = *(p+1);
}
--len;
--col;
--cp;
c_output( ' ', plen+len, line, normal);
s_output( cp, line, col, color );
*(answer + len) = '\0';
}
break;
case DeleteChar :
/*
* delete char under cursor
*/
if (*cp) {
for (p=cp; p < answer+len; p++) {
*p = *(p+1);
}
--len;
c_output( ' ', plen+len, line, normal);
s_output( cp, line, col, color );
*(answer + len) = '\0';
}
break;
case DeleteLine :
/*
* delete current line
*/
col = plen;
cp = answer;
*cp = '\0';
len = 0;
eol_clear( col, line, normal );
break;
case RestoreString :
/*
* restore original line
*/
strcpy( answer, name );
len = strlen( answer );
col = plen + len;
cp = answer + len;
s_output( cp, line, col, color );
break;
case CharLeft :
/*
* move cursor left
*/
if (cp > answer) {
col--;
cp--;
}
break;
case CharRight :
/*
* move cursor right
*/
if (*cp) {
col++;
cp++;
}
break;
case BegOfLine :
/*
* move cursor to start of line
*/
col = plen;
cp = answer;
break;
case EndOfLine :
/*
* move cursor to end of line
*/
col = plen + len;
cp = answer + len;
break;
default :
if (c < 0x100) {
/*
* insert character at cursor
*/
if (first) {
/*
* delete previous answer
*/
col = plen;
cp = answer;
*cp = '\0';
len = 0;
eol_clear( col, line, normal );
}
/*
* insert new character
*/
if (col < g_display.ncols-1) {
if (*cp == '\0') {
++len;
*(answer + len) = '\0';
}
*cp = c;
c_output( c, col, line, color );
++cp;
++col;
}
}
break;
}
first = FALSE;
}
restore_screen_line( 0, line, line_buff );
if (key_func[c].func == AbortCommand)
c = ERROR;
else
c = OK;
return( c );
}
/*
* Name: get_yn
* Purpose: To input a response of yes or no.
* Date: October 1, 1989
* Returns: the user's answer (A_??? - see tdestr.h)
*/
int get_yn( )
{
int c; /* the user's response */
int rc; /* return code */
xygoto( g_status.prompt_col, g_status.prompt_line );
for (rc=-1; rc<0;) {
c = (c=getch()) != 0 ? c : getch() | 0x100;
if (key_func[c].func == AbortCommand)
rc = A_ABORT;
else {
switch ( c ) {
case 'Y':
case 'y':
rc = A_YES;
break;
case 'N':
case 'n':
rc = A_NO;
break;
}
}
}
return( rc );
}
/*
* Name: get_oa
* Purpose: To input a response of overwrite or append.
* Date: October 1, 1989
* Returns: the user's answer (A_??? - see tdestr.h)
*/
int get_oa( )
{
int c; /* the user's response */
int rc; /* return code */
rc = 0;
while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
xygoto( g_status.prompt_col, g_status.prompt_line );
c = (c=getch()) != 0 ? c : getch() | 0x100;
c_output( c, g_display.col, g_display.line, g_display.message_color );
if (key_func[c].func == AbortCommand)
rc = A_ABORT;
switch ( c ) {
case 'O':
case 'o':
rc = A_OVERWRITE;
break;
case 'A':
case 'a':
rc = A_APPEND;
break;
}
}
return( rc );
}
/*
* Name: display_current_window
* Purpose: display text in current window
* Date: June 5, 1991
* Passed: window: current window
* Notes: use a temporary window structure, "w", to do the dirty work.
*/
void display_current_window( window )
windows *window;
{
text_ptr prev, p; /* successive lines above the cursor */
int count; /* number of lines updated so far */
int number; /* number of lines visible in window */
int attr;
int i;
windows w;
/*
* work out how many lines need to be displayed
*/
number = window->bottom_line - (window->top_line - 1);
/*
* display the required number of lines, starting from the
* cursor line
*/
dup_window_info( &w, window );
w.cursor = cpb( w.cursor );
count = window->cline - window->top_line;
for (i=count; i>0; i--) {
p = find_prev( w.cursor );
if (p) {
w.cursor = p;
--w.cline;
--w.rline;
}
}
attr = g_display.text_color;
w.cursor = cpf( w.cursor );
for (i=number; i>0; i--) {
if (w.cursor) {
update_line( &w );
w.cursor = find_next( w.cursor );
} else
eol_clear( 0, w.cline, attr );
++w.cline;
++w.rline;
}
}
/*
* Name: redraw_screen
* Purpose: display all visible windows if some change was GLOBAL
* Date: June 5, 1991
* Passed: window: current window
*/
void redraw_screen( window )
windows *window;
{
windows *above; /* window above current */
windows *below; /* window below current */
/*
* display the current window
*/
display_current_window( window );
/*
* now update all the other windows
*/
above = below = window;
while (above->prev || below->next) {
if (above->prev) {
above = above->prev;
if (window->dirty == GLOBAL && above->visible)
display_current_window( above );
}
if (below->next) {
below = below->next;
if (window->dirty == GLOBAL && below->visible)
display_current_window( below );
}
}
window->dirty = FALSE;
}
/*
* Name: show_changed_line
* Purpose: Only one line was changed in file, just show it
* Date: June 5, 1991
* Passed: window: current window
*/
void show_changed_line( window )
windows *window;
{
windows *above; /* window above current */
windows *below; /* window below current */
windows w;
long changed_line;
long top_line, bottom_line;
int line_on_screen;
if (window->dirty == LOCAL || window->dirty == GLOBAL)
update_line( window );
changed_line = window->rline;
/*
* now update the line in all other windows
*/
if (window->dirty != LOCAL) {
above = below = window;
while (above->prev || below->next) {
if (above->prev) {
above = above->prev;
dup_window_info( &w, above );
} else if (below->next) {
below = below->next;
dup_window_info( &w, below );
}
if (w.file_info == window->file_info && w.visible) {
line_on_screen = FALSE;
top_line = w.rline - (w.cline - w.top_line);
bottom_line = w.rline + (w.bottom_line - w.cline);
if (changed_line == w.rline)
line_on_screen = TRUE;
else if (changed_line < w.rline && changed_line >= top_line) {
line_on_screen = TRUE;
w.cursor = cpb( w.cursor );
while (w.rline > changed_line) {
w.cursor = find_prev( w.cursor );
--w.rline;
--w.cline;
}
} else if (changed_line > w.rline && changed_line <= bottom_line) {
line_on_screen = TRUE;
w.cursor = cpf( w.cursor );
while (w.rline < changed_line) {
w.cursor = find_next( w.cursor );
++w.rline;
++w.cline;
}
}
if (line_on_screen)
update_line( &w );
}
}
}
window->dirty = FALSE;
}
/*
* Name: dup_window_info
* Purpose: Copy window info from one window pointer to another
* Date: June 5, 1991
* Passed: dw: destination window
* sw: source window
*/
void dup_window_info( dw, sw )
windows *dw, *sw;
{
memcpy( dw, sw, sizeof( windows ) );
}
/*
* Name: adjust_windows_cursor
* Purpose: A change has been made - window->cursors in other windows must
* be changed to reflect adding or subing of characters.
* Date: June 5, 1991
* Passed: window: current window
* net_change: number of bytes added or subtracted from a file
* line_change: number of lines added or subtracted from a file
* Notes: If a file has been changed, all of the memory pointers greater
* than window->cursor must be adjusted by the number of characters
* added or subtracted from the file pointed to by window.
* If a file has been truncated in one window and there is another
* window open to the same file and its current line is near the
* end, the current line is reset to the last line of the file.
*/
void adjust_windows_cursor( window, net_change, line_change )
windows *window;
long net_change;
int line_change;
{
windows *next;
int reset;
text_ptr p;
int i;
file_infos *file;
file_infos *next_file;
file = window->file_info;
next = g_status.window_list;
while (next != NULL) {
if (next != window) {
next_file = next->file_info;
if (next_file == file) {
reset = FALSE;
if (ptoul( next->cursor ) > ptoul( file->end_text ))
reset = END;
else if (ptoul( next->cursor ) < ptoul( file->start_text ))
reset = BEGIN;
else if (next->rline > window->rline) {
next->cursor = addltop( net_change, next->cursor );
if (line_change) {
p = next->cursor;
if (line_change < 0) {
p = cpf( p );
for (i=line_change; i < 0 && p != NULL; i++)
p = find_next( p );
if (p != NULL)
next->cursor = p;
else
reset = END;
} else if (line_change > 0) {
p = cpb( p );
for (i=line_change; i > 0 && p != NULL; i--)
p = find_prev( p );
if (p != NULL)
next->cursor = p;
else
reset = BEGIN;
}
}
}
if (reset) {
if (reset == BEGIN) {
next->cursor = next_file->start_text;
next->rline = 1;
next->cline = next->top_line;
} else {
next_file->end_text = cpb( next_file->end_text );
p = next_file->end_text - 1;
p = find_prev( p );
if (p != NULL)
next->cursor = p;
else
next->cursor = next_file->end_text - 1;
next->rline = next_file->length;
}
if (next->rline < (next->cline - (next->top_line - 1)))
next->cline = next->rline + next->top_line - 1;
window->dirty = NOT_LOCAL;
}
} else {
if (ptoul( next_file->start_text ) > ptoul( file->start_text ))
next->cursor = addltop( net_change, next->cursor );
}
}
next = next->next;
}
}
/*
* Name: adjust_start_end
* Purpose: a file has been modified - must restore all start and end pointers
* Date: June 5, 1991
* Passed: mod: pointer to modified file structure
* net_mod: net modifications in the source file
* Notes: Go through the file list and adjust the start_text and end_text
* file pointers as needed.
*/
void adjust_start_end( mod_file, net_mod )
file_infos *mod_file;
long net_mod;
{
unsigned long mst, ost;
file_infos *open_file;
mst = ptoul( mod_file->start_text );
for (open_file=g_status.file_list; open_file != NULL;
open_file=open_file->next) {
ost = ptoul( open_file->start_text );
if (ost == mst)
mod_file->end_text = addltop( net_mod, mod_file->end_text );
else if (ost > mst) {
open_file->start_text = addltop( net_mod, open_file->start_text );
open_file->end_text = addltop( net_mod, open_file->end_text );
}
}
}
/*
* Name: first_non_blank
* Purpose: To find the column in which the first non-blank character in
* the string occurs.
* Date: June 5, 1991
* Passed: s: the string to search
* Returns: the first non-blank column
*/
int first_non_blank( s )
char *s;
{
int count = 0;
s = cpf( s );
while (*s++ == ' ')
++count;
return( count );
}
/*
* Name: page_up
* Purpose: To move the cursor one page up the window (probably more
* intuitive to think of the text being moved down)
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: The cursor line is moved back the required number of lines
* towards the start of the file.
* If the start of the file is reached, then the movement stops.
*/
void page_up( window )
windows *window;
{
int i; /* count of lines scanned */
text_ptr p, q; /* previous lines */
if (window->rline != (window->cline - (window->top_line-1))) {
q = cpb( window->cursor );
i = window->cline - (window->top_line-1);
if (( window->rline - i) < window->page) {
i = window->rline - (window->cline - (window->top_line-1));
for (; i>0; i--) {
if ((p = find_prev( q )) != NULL)
q = p;
}
window->rline = (window->cline-(window->top_line-1)) + window->page;
} else {
for (i=window->page; i>0; i--) {
if ((p = find_prev( q )) != NULL)
q = p;
}
}
window->cursor = q;
window->rline -= window->page;
window->dirty = LOCAL;
}
}
/*
* Name: page_down
* Purpose: To move the cursor one page down the window (probably more
* intuitive to think of the text being moved up)
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: The cursor line is moved forwards the required number of lines
* towards the end of the file.
* If the end of the file is reached, then the movement stops.
*/
void page_down( window )
windows *window;
{
int i, k; /* count of lines scanned so far */
text_ptr p, q; /* lines below cursor */
q = cpf( window->cursor );
k = window->cline - window->top_line;
for (i=0; i < window->page && *q != CONTROL_Z; i++, k++) {
p = find_next( q );
if (p != NULL)
q = p;
else
break;
}
if (k >= window->page) {
window->cursor = q;
window->rline += i;
window->cline = window->cline + i - window->page;
window->dirty = LOCAL;
}
}
/*
* Name: scroll_down
* Purpose: To make the necessary changes after the user has given the
* command to scroll down the screen.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: Normally, we can just delete the top line on the window, and
* then move the cursor up one line (so the cursor remains at
* the same position in the file).
* However, if the cursor was already on the top line of the
* window, then the cursor must be moved down a line first.
*/
void scroll_down( window )
windows *window;
{
text_ptr next;
window->cursor = cpf( window->cursor );
if (window->cline == window->top_line) {
if ((next = find_next( window->cursor )) != NULL)
window->cursor = next;
else
return;
++window->cline;
++window->rline;
}
--window->cline;
window->dirty = LOCAL;
}
/*
* Name: scroll_up
* Purpose: To make the necessary changes after the user has given the
* command to scroll up the screen.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: Normally, we can just insert one line at the top of the window,
* and then move the cursor down one line (so the cursor remains at
* the same position in the file).
* However, if the cursor was already on the bottom line of the
* window, then the cursor must be moved up a line first.
*/
void scroll_up( window )
windows *window;
{
text_ptr prev;
window->cursor = cpb( window->cursor );
if (window->rline != 1) {
if (window->rline == (window->cline - (window->top_line -1))) {
if ((prev = find_prev( window->cursor )) != NULL)
window->cursor = prev;
--window->rline;
--window->cline;
} else {
if (window->cline == window->bottom_line) {
if ((prev = find_prev( window->cursor )) != NULL)
window->cursor = prev;
else
return;
--window->cline;
--window->rline;
}
++window->cline;
window->dirty = LOCAL;
}
}
}
/*
* Name: save_file
* Purpose: To save the current file to disk.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If anything goes wrong, then the modified flag is set.
* If the file is saved successfully, then modified flag is
* cleared.
*/
void save_file( window )
windows *window;
{
char name[MAX_COLS]; /* name of file to be saved */
char status_line[MAX_COLS+2]; /* status line at top of window */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
file_infos *file;
int rc;
int prompt_line;
prompt_line = window->bottom_line;
/*
* set up file name and location of various flags
*/
file = window->file_info;
strcpy( name, file->file_name );
/*
* see if there was a file name - if not, then make the user
* supply one.
*/
if (strlen( name ) == 0) {
save_as_file( window );
return;
}
/*
* save the file
*/
save_screen_line( 0, prompt_line, line_buff );
combine_strings( status_line, "Saving '", name, "'" );
s_output( status_line, prompt_line, 0, g_display.message_color );
eol_clear( strlen( status_line ), prompt_line, g_display.message_color );
file->end_text = cpb( file->end_text );
if ((rc = hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
prompt_line )) == ERROR) {
combine_strings( status_line, "cannot write to '", name, "'" );
error( WARNING, prompt_line, status_line );
}
restore_screen_line( 0, prompt_line, line_buff );
if (rc != ERROR) {
file->modified = FALSE;
file->new_file = FALSE;
}
}
/*
* Name: save_as_file
* Purpose: To save the current file to disk, but under a new name.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
*/
void save_as_file( window )
windows *window;
{
char name[MAX_COLS]; /* new name for file */
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
char status_line[MAX_COLS+2]; /* status line at top of window */
file_infos *file;
int prompt_line;
int ok;
/*
* read in name, no default
*/
prompt_line = window->bottom_line;
file = window->file_info;
save_screen_line( 0, prompt_line, line_buff );
name[0] = '\0';
if (get_name( "New file name: ", prompt_line, name,
g_display.message_color ) == OK) {
/*
* make sure it is OK to overwrite any existing file
*/
ok = TRUE;
if (hw_fattrib( name ) != ERROR) { /* file exists */
set_prompt( "Overwrite existing file? (y/n): ", prompt_line );
if (get_yn( ) != A_YES || hw_unlink( name, prompt_line ) == ERROR)
ok = FALSE;
}
if (ok == TRUE) {
combine_strings( status_line, "Saving '", name, "'" );
s_output( status_line, prompt_line, 0, g_display.message_color );
eol_clear( strlen( status_line ), prompt_line,
g_display.message_color );
file->end_text = cpb( file->end_text );
if (hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
prompt_line ) == ERROR) {
combine_strings( status_line, "cannot write to '", name, "'" );
error( WARNING, prompt_line, status_line );
} else
/*
* record that file is saved and not yet modified again
*/
file->modified = FALSE;
}
}
restore_screen_line( 0, prompt_line, line_buff );
}
/*
* Name: show_window_header
* Purpose: To save the current file to disk, but under a new name.
* Date: June 5, 1991
* Passed: name: name of file being edited
* window: information allowing access to the current window
* Notes: Clear line and display file name in a lite bar
*/
void show_window_header( name, window )
char *name;
windows *window;
{
char status_line[MAX_COLS+2]; /* status line at top of window */
char *p, *q; /* for setting up status line */
memset( status_line, ' ', MAX_COLS );
status_line[MAX_COLS] = '\0';
q = name;
p = status_line + 2;
while (*q)
*p++ = *q++;
s_output( status_line, window->top_line-1, 0, g_display.head_color );
}
/*
* Name: show_size_name
* Purpose: show 'size' line lite bar header
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
*/
void show_size_name( window )
windows *window;
{
char size_line[MAX_COLS+2]; /* status line at top of window */
strcpy( size_line, " size = " );
s_output( size_line, window->top_line-1, 49, g_display.head_color );
}
/*
* Name: show_size
* Purpose: show number of lines in file
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
*/
void show_size( window )
windows *window;
{
char size_line[MAX_COLS+2]; /* status line at top of window */
char csize[20];
char *p, *q; /* for setting up status line */
strcpy( size_line, " " );
p = size_line;
ltoa( window->file_info->length, csize, 10 );
q = csize;
while (*q)
*p++ = *q++;
*p++ = ' ';
*p = '\0';
s_output( size_line, window->top_line-1, 57, g_display.head_color );
}
/*
* Name: quit
* Purpose: To close the current window without saving the current file.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If the file has been modified but not saved, then the user is
* given a second chance before the changes are discarded.
* Note that this is only necessary if this is the last window
* that refers to the file. If another window still refers to
* the file, then the check can be left until later.
*/
void quit( window, stop )
windows *window;
int *stop;
{
int prompt_line;
char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute */
file_infos *file;
windows *wp;
int count = 0;
prompt_line = window->bottom_line;
file = window->file_info;
for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
if (wp->file_info == file && wp->visible)
++count;
}
if (file->modified && count == 1) {
save_screen_line( 0, prompt_line, line_buff );
set_prompt( "Abandon changes? (y/n): ", prompt_line );
if (get_yn( ) != A_YES) {
restore_screen_line( 0, prompt_line, line_buff );
return;
}
}
/*
* remove window, allocate screen lines to other windows etc
*/
finish( window, stop );
}
/*
* Name: move_up
* Purpose: To move the cursor one line up the screen.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If the cursor is at the top of the window, then the file must
* be scrolled down.
* If the cursor is already on the first line of the file, then
* this command can be ignored.
*/
void move_up( window )
windows *window;
{
text_ptr p; /* the previous line on the screen */
/*
* if no previous line, give up
*/
window->cursor = cpb( window->cursor );
if ((p = find_prev( window->cursor )) != NULL) {
window->cursor = p;
--window->rline; /* ALWAYS decrement line counter */
if (window->cline == window->top_line) {
window_scroll_down( window->top_line, window->bottom_line );
update_line( window );
} else
--window->cline; /* we aren't at top of screen - so move up */
}
}
/*
* Name: move_down
* Purpose: To move the cursor one line down the screen.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If the cursor is at the bottom of the window, then the file must
* be scrolled up. If the cursor is at the bottom of the file,
* then scroll up until cursor is at top of screen.
*/
void move_down( window )
windows *window;
{
text_ptr p;
int bottom_line;
bottom_line = window->bottom_line;
window->cursor = cpf( window->cursor );
if ((p = find_next( window->cursor )) != NULL) {
window->cursor = p;
++window->rline; /* ALWAYS increment line counter */
if (window->cline == bottom_line) {
window_scroll_up( window->top_line, bottom_line );
update_line( window );
} else
++window->cline; /* if not at bottom of screen move down */
} else if (window->cline > window->top_line) {
--window->cline;
window_scroll_up( window->top_line, bottom_line );
}
}
/*
* Name: move_left
* Purpose: To move the cursor one character to the left
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If the cursor is already at the left of the screen, then
* scroll horizontally if we're not at beginning of line.
*/
void move_left( window )
windows *window;
{
if (window->ccol > 0) {
--window->ccol;
--window->rcol;
} else if (window->ccol == 0 && window->rcol > 0) {
--window->rcol;
--window->bcol;
window->dirty = LOCAL;
}
}
/*
* Name: move_right
* Purpose: To move the cursor one character to the right
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: If the cursor is already at the right of the screen (logical
* column 80) then scroll horizontally right.
*/
void move_right( window )
windows *window;
{
int max_col;
max_col = g_display.ncols - 1;
if (window->ccol < max_col) {
++window->ccol;
++window->rcol;
} else if (window->ccol == max_col && window->rcol < g_display.line_length) {
++window->rcol;
++window->bcol;
window->dirty = LOCAL;
}
}
/*
* Name: word_left
* Purpose: To move the cursor one word to the left.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: Words are considered strings of letters, numbers and underscores,
* which must be separated by other characters.
*/
void word_left( window )
windows *window;
{
text_ptr p; /* text pointer */
int len; /* length of current line */
int c; /* character at pointer */
int check = 0;
p = cpb( window->cursor );
len = linelen( p );
if (window->rcol > len)
p += len;
else
p += window->rcol;
for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
c = *--p;
if (check > 8000) {
p = cpb( p );
check = 0;
}
}
if (c == CONTROL_Z)
return;
for (; c != CONTROL_Z && !myisalnum( c ); check++) {
c = *--p;
if (check > 8000) {
p = cpb( p );
check = 0;
}
}
if (c == CONTROL_Z)
return;
for (;c != CONTROL_Z && myisalnum( c ); check++) {
c = *--p;
if (check > 8000) {
p = cpb( p );
check = 0;
}
}
find_adjust( window, ++p );
}
/*
* Name: word_right
* Purpose: To move the cursor one word to the right.
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Notes: Words are considered strings of letters, numbers and underscores,
* which must be separated by other characters.
*/
void word_right( window )
windows *window;
{
int len; /* length of current line */
text_ptr p; /* text pointer */
int c; /* character at pointer */
int check;
p = cpb( window->cursor );
len = linelen( p );
if (window->rcol > len)
p += len;
else
p += window->rcol;
for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
c = *++p;
if (check > 8000) {
p = cpf( p );
check = 0;
}
}
for (; c != CONTROL_Z && !myisalnum( c ); check++) {
c = *++p;
if (check > 8000) {
p = cpf( p );
check = 0;
}
}
if (c != CONTROL_Z)
find_adjust( window, p );
}